package pub.dsb.example.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>
 *
 * </p>
 *
 * @author Yi
 * @version V1.0.0
 * @date 2020/12/29 16:49
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify By: {修改人} 2020/12/29 16:49
 * @modify reason: {方法名}:{原因}
 * ...
 * @since V1.0.0
 */
public class LC1114Test {

    public static void main(String[] args) throws InterruptedException {
        Integer[] input = new Integer[]{1, 3, 2};
        doAsyncPrint(input);
        input = new Integer[]{1, 2, 3};
        doAsyncPrint(input);
    }


    private static void doAsyncPrint(Integer[] input) throws InterruptedException {
        Foo2 foo = new Foo2();
        List<Runnable> threads = new ArrayList<>();
        Runnable first = () -> {
            try {
                foo.doFirst();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Runnable second = () -> {
            try {
                foo.doSecond();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Runnable third = () -> {
            try {
                foo.doThird();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        threads.add(first);
        threads.add(second);
        threads.add(third);
        String[] threadNameArr = new String[]{"A", "B", "C"};
        int index = 0;
        for (String tName : threadNameArr) {
            int tIndex = input[index++] - 1;
            new Thread(threads.get(tIndex)
                    , tName).start();
        }
        Thread.sleep(5000);
    }

    static class Foo {

        private AtomicInteger first = new AtomicInteger(0);
        private AtomicInteger second = new AtomicInteger(0);

        public Foo() {
            first.set(0);
            second.set(0);
        }

        public void doFirst() {
            first();
            first.incrementAndGet();
        }

        public void doSecond() {
            while (first.get() != 1) {
            }
            second();
            second.incrementAndGet();
        }

        public void doThird() {
            while (second.get() != 1) {
            }
            third();
        }

        public void first() {
            print("first");
        }

        private void print(String msg) {
            System.out.println(Thread.currentThread().getName() + ": " + msg);
        }

        public void second() {
            print("second");
        }

        public void third() {
            print("third");
        }
    }


    static class Foo2 {

        private volatile int flag = 1;

        private final Object lock = new Object();

        public Foo2() {
        }

        public void doFirst() throws InterruptedException {
            synchronized (lock) {
                while (flag != 1) {
                    lock.wait();
                }
                first();
                flag = 2;
                lock.notifyAll();
            }
        }

        public void doSecond() throws InterruptedException {
            synchronized (lock) {
                while (flag != 2) {
                    lock.wait();
                }
                second();
                flag = 3;
                lock.notifyAll();
            }
        }

        public void doThird() throws InterruptedException {
            synchronized (lock) {
                while (flag != 3) {
                    lock.wait();
                }
            }
            third();
        }

        public void first() {
            print("first");
        }

        private void print(String msg) {
            System.out.println(Thread.currentThread().getName() + ": " + msg);
        }

        public void second() {
            print("second");
        }

        public void third() {
            print("third");
        }
    }
}

/**
 * LEETCODE 1114 方式1
 */
class Foo {

    private volatile int flag = 1;

    private final Object lock = new Object();

    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {

        synchronized (lock) {
            while (flag != 1) {
                lock.wait();
            }
            // printFirst.run() outputs "first". Do not change or remove this line.
            printFirst.run();
            flag = 2;
            lock.notifyAll();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException {

        synchronized (lock) {
            while (flag != 2) {
                lock.wait();
            }
            // printSecond.run() outputs "second". Do not change or remove this line.
            printSecond.run();
            flag = 3;
            lock.notifyAll();
        }
    }

    public void third(Runnable printThird) throws InterruptedException {
        synchronized (lock) {
            while (flag != 3) {
                lock.wait();
            }
        }
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
    }
}

/**
 * LEETCODE 1114 方式2
 */
class Foo2 {

    private AtomicInteger first = new AtomicInteger(0);
    private AtomicInteger second = new AtomicInteger(0);

    public Foo2() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
        // printFirst.run() outputs "first". Do not change or remove this line.
        printFirst.run();
        first.incrementAndGet();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while (first.get() != 1) {
        }
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
        second.incrementAndGet();
    }

    public void third(Runnable printThird) throws InterruptedException {
        while (second.get() != 1) {
        }
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
    }
}